/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package systemsim;

import java.util.*;
import javax.swing.JOptionPane;

/**
 * The RestaurantQueue represents the line of people waiting to get inside.
 * It is responsible for spawning new customers in accordance with the specified rates
 * It handles the different spawn rates associated with opening, peak time, and closing time.
 * @author emil
 */
public class RestaurantQueue {
    
    private GUIQueue guiQueue;
 
    private int numOfExpectedCustomers;
    private int hrsRestIsOpen;
    private int hrsRushHourDuration;
    private int averageEatingTime;
    private long startTime;
    
    private long startOfRushHour;
    private long endOfRushHour;
    
    private int rushHourRate=3;
    private int regualrRate=1;
    
    private int threadRate=500; // Thread runs every 500 milliseconds
    
    private LinkedList<Group> waitingLine = (new LinkedList<Group>());
    
    public static Timer queueProcess = new Timer();
    
    
    public RestaurantQueue(int numExpctdCustmrs, int hrsOpen, int hrsRush, int averageEatingTime)
    {
        this.numOfExpectedCustomers = numExpctdCustmrs;
        this.hrsRestIsOpen = hrsOpen;
        this.hrsRushHourDuration = hrsRush;
        this.startTime = System.currentTimeMillis();

        this.averageEatingTime = averageEatingTime;

        this.setRushHourTimes();
        
        guiQueue = new GUIQueue();
        
        queueProcess.schedule(new QueueTask(),200,threadRate);
    }
    
    /**Calculates the start and end times of rush hour
     */
    private void setRushHourTimes()
    {
        if(this.hrsRestIsOpen <= this.hrsRushHourDuration )
        {
            //n/a
        }
        else
        {
            long nonPeakHrs = this.hrsRestIsOpen - this.hrsRushHourDuration;
            nonPeakHrs = nonPeakHrs/2;
            
            this.startOfRushHour = startTime + nonPeakHrs*3600L*1000L/Main.TIMESCALE;
            this.endOfRushHour = startTime + (nonPeakHrs+this.hrsRushHourDuration)*3600L*1000L/Main.TIMESCALE;
            
        }
    }
    
    /**
     * returns true if it's rush hour time
     */
    public boolean isRushHour()
    {
        if(System.currentTimeMillis() < this.startOfRushHour || System.currentTimeMillis() > this.endOfRushHour)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    /**
     * gets the size of the line of people outside.
     */
    public int getSizeOfQueue()
    {
        return waitingLine.size();
    }

    /**
     * Gets the actual LinkedList which represents the line of peopple
     * intended use is for the gui. The gui can get the line and go
     * through each group in the line and display the stats.
     */
    public LinkedList<Group> getActaulWaitingLine() {
        return waitingLine;
    }
   
    
    
    private class QueueTask extends java.util.TimerTask
    {
        private long closeTime = startTime+hrsRestIsOpen*3600L*1000L/Main.TIMESCALE;
        private int customersLeftToProcess = numOfExpectedCustomers;
        private Random rand = new Random();
        
        public void run()
        {
            //System.out.println("QueueRun");
            long currTime = System.currentTimeMillis();
            
            
            //If the restaurant has closed, end the simulation
            if(closeTime <= currTime)
            {
                //TODO
                //Stop the simulation... but dont close the JFrames... hmm?(actually i have an idea for this-- cancel)
                    //-stop kitchen
                    //-stop restaurant
                    //-stop this
                
                System.out.println("SIMULATION OVER - TIME OVER");
                queueProcess.cancel();
                MainMenu.theKitchen.kitchenProcess.cancel();
                MainMenu.theRestaurant.restaurantProcess.cancel();
                JOptionPane.showMessageDialog(null,"TIME OVER!\n"+this.customersLeftToProcess +" Customers were not accounted for.\n"+waitingLine.size()+" are left outside in the Queue");
                
                
            }
            
            //===============================================//
            //===============================================//
            
            int numOfPpl;
            //If the specified number of expected customers has not been reached, continue
            if(customersLeftToProcess > 0)
            {
                //System.out.println("QueueRun2");
                

                //Generate a new group to get in line for the restaurant
                //in accordance to rush hour rates
                
                int threadRun = 1000 / threadRate;  //gives #of times the thread runs in 1 second
                
                //If in rush hour, generate group more often
                if(isRushHour())
                {
                    //if(rand.nextInt(threadRun+1) >= threadRun/2 )
                    if(rand.nextInt(20) >= 15)
                    {
                        numOfPpl = rand.nextInt(9)+1;
                        //Group(int ID, int numPeople, int averageEatingTime)
                        Group group = new Group(customersLeftToProcess, numOfPpl, averageEatingTime);
                        customersLeftToProcess--;
                        waitingLine.add(group);
                        guiQueue.add(group);
                        System.out.println("Arrival of group"+group+"Rshr");
                        
                    }
                    
                }
                
                //else more slowly
                else
                {
                    //if(rand.nextInt(threadRun+6) > (threadRun/2)+1 )
                    if(rand.nextInt(20) > 18)
                    {
                        numOfPpl = rand.nextInt(9)+1;
                        //Group(int ID, int numPeople, int averageEatingTime)
                        Group group = new Group(customersLeftToProcess, numOfPpl, averageEatingTime);
                        customersLeftToProcess--;
                        waitingLine.add(group);
                        guiQueue.add(group);
                        System.out.println("Arrival of group"+group+"NORshr");
                        System.out.println("Size of line outside is "+waitingLine.size());
                        
                    }
                    
                }
                 
                //===============================================//

                
                
            }
            
            //send next waiting in line group in the restaurant.
            //the restaurant may not take them if it is full.
            if(!waitingLine.isEmpty())
            {
                //System.out.println("QueueRun3");
                //Change from Main to MainMenu
                if((MainMenu.theRestaurant.attemptToSitCustomers(waitingLine.getFirst())) == true)
                {
                    //System.out.println(Main.theRestaurant.attemptToSitCustomers(waitingLine.getFirst()));
                    //System.out.println("Accepted Group "+waitingLine.getFirst());
                    guiQueue.remove(waitingLine.getFirst());
                    waitingLine.removeFirst();
                }
            }
            
            
            guiQueue.setSizeDisplay(waitingLine.size(), isRushHour());
            
            
            
            
            
        }
    }
    
}
